-module(aleph_dht_session).
-include("aleph_data_interface.hrl").
-include("aleph_naming_macros.hrl").
-include_lib("eunit/include/eunit.hrl"). 

-export([start/0,new_session/1,find_session/1,delete_session/1,insert_session/1,
         clear_sessions/0,set_answered/3,set_found/3,set_queried/3,is_queried_has_id/2,
         is_answered_has_id/2,set_finished/1,set_outstanding/2,get_outstanding/1]).
-export([session_test/0,setter_test/0]).
start()->
   case ets:info(?DHT_SESSION_TAB) of
        [{_,_}|_]->clear_sessions();                      
        undefined->continue
   end,     
   ets:new(?DHT_SESSION_TAB,[named_table,protected,ordered_set,{keypos,1}]),
   ok.

set_answered(Key,Node_id,Is_answered)when ?IS_OBJECT(Key)==true->
    set_answered(Key(key),Node_id,Is_answered);    
set_answered(Key,Node_id,Is_answered)->
  set_dict_field(Key,answered,Node_id,Is_answered).

set_found(Key,Node_id,Node)when ?IS_OBJECT(Key)==true->
    set_found(Key(key),Node_id,Node);   
set_found(Key,Node_id,Node)->
  set_dict_field(Key,found,Node_id,Node).  

set_queried(Key,Node_id,Is_queried)when ?IS_OBJECT(Key)==true->
    set_queried(Key(key),Node_id,Is_queried); 
set_queried(Key,Node_id,Is_queried)->
    set_dict_field(Key,queried,Node_id,Is_queried).
 
is_answered_has_id(Key,Node_id)when ?IS_OBJECT(Key)==true->
    is_answered_has_id(Key(key),Node_id);
is_answered_has_id(Key,Node_id)->
   {_,Answered}=get_field(Key,answered),    
   dict:is_key(Node_id, Answered).

is_queried_has_id(Key,Node_id)when ?IS_OBJECT(Key)==true->
    is_queried_has_id(Key(key),Node_id);
is_queried_has_id(Key,Node_id)->
   {_,Queried}=get_field(Key,queried),    
   dict:is_key(Node_id,Queried).

set_finished(Key)when ?IS_OBJECT(Key)==true->
    set_finished(Key(key));
set_finished(Key)->
    set_field(Key,finished,true).

set_outstanding(Key,Data)when ?IS_OBJECT(Key)==true->
    set_outstanding(Key(key),Data);
set_outstanding(Key,Data)->
    set_field(Key,outstanding,Data).

get_outstanding(Key)when ?IS_OBJECT(Key)==true->
    get_outstanding(Key(key));
get_outstanding(Key)->
    Session=find_session(Key),
    Session(outstanding).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
new_session(Target)->
    Key=make_key(Target),
    Session=session:create(Key,Target,false,dict:new(),dict:new(),-1,dict:new()),
    insert_session(Session),
    Session.

find_session(Key)when ?IS_OBJECT(Key)==true->
    find_session(Key(key));
find_session(Key)->
    case ets:lookup(?DHT_SESSION_TAB,Key) of
    [{_,Session}|_]->Session;
                []->[]
    end.
insert_session(Session)->
    case ets:insert(?DHT_SESSION_TAB,{Session(key),Session}) of
        true->Session;
        fase->none
    end.

delete_session(Key)when ?IS_OBJECT(Key)==true->
    delete_session(Key(key));
delete_session(Key)->
    ets:delete(?DHT_SESSION_TAB,Key).

clear_sessions()->
    ets:db_delete(?DHT_SESSION_TAB),
    ok.

%%%%%%%%%%%%%%%%%%%
make_key(Id)->
   Data=term_to_binary({Id,aleph_utility:time_stamp(milliseconds)}),
   crypto:sha_final(crypto:sha_update(crypto:sha_init(),Data)).



get_field(Key,Name)->   
     Session=find_session(Key),
     {Session,Session(Name)}.
set_dict_field(Key,Field,Id,Data)->
    {Session,Dict}=get_field(Key,Field),
    NewDict=dict:store(Id,Data,Dict),
    insert_session(Session({Field,NewDict})).
set_field(Key,Field,Data)->
    Session=find_session(Key),
    insert_session(Session({Field,Data})).      

session_test()->
    start(),
    Session=new_session(111),
    Session2=find_session(Session(key)),
    ?match(true,Session(key)=:=Session2(key)),
    delete_session(Session(key)),
    Session3=find_session(Session(key)),
    ?match(true,Session3=:=[]),
    clear_sessions(),
    ok.
setter_test()->
     start(),
     Session=new_session(111),
     set_answered(Session,99999,1000),
     set_found(Session,9998,"1111"),
     set_queried(Session,9997,"tttt"),
     set_finished(Session),
     set_outstanding(Session,"uuuu"),
     Session2=find_session(Session),
     Answered=Session2(answered),
     Found=Session2(found),
     Queried=Session2(queried),
     Value=dict:fetch(99999,Answered),
     ?match(true,Value==1000),
     Value2=dict:fetch(9998,Found),
      ?match(true,Value2=:="1111"),
     Value3=dict:fetch(9997,Queried),   
     ?match(true,Value3=:="tttt"),    
     ?match(true,Session2(outstanding)=:="uuuu"),
     ?match(true,Session2(finished)==true),
     Has_key=is_answered_has_id(Session2,99999),
     ?match(true,Has_key),
     clear_sessions(),
     ok.

     